package main

import (
	"errors"
	"fmt"
	"strings"
)

type LogicalDeviceMap map[string]LogicalActionMap
type LogicalActionMap map[string]*LogicalExpr

func (ldm LogicalDeviceMap) GetLogicalExpr(device, action string) (*LogicalExpr, error) {
	if lam, ok := ldm[device]; ok {
		if le, ok := lam[action]; ok {
			return le, nil
		}
	}
	return nil, errors.New("无法找到对应的逻辑")

}

type Expression struct {
	str      string
	expr     []string
	line     int
	filePath string
	FullStr  string
}

func (e *Expression) Marshal() {
	if len(e.expr) == 0 {
		return
	}
	e.str = e.expr[0]
	for i := range e.expr[1:] {
		e.str = e.str + "," + e.expr[i]
	}
}
func (e *Expression) Unmarshal() {
	strSlice := strings.Split(e.str, SEPARATOR)
	e.expr = RemoveDuplicateElement(strSlice)
}

func (e *Expression) findSameExpr(multipleExpr []*Expression) int {
	for i := range multipleExpr {
		if CompareSlice(e.expr, multipleExpr[i].expr) {
			return i
		}
	}
	return -1
}

func (e *Expression) Clone() *Expression {
	var cExpr *Expression
	cExpr = e
	return cExpr
}

type LogicalExpr struct {
	filePath          string
	FullStr           string
	Line              int
	device            string
	action            string
	CaseMultipleExpr  []*Expression
	LogicMultipleExpr []*Expression
	indexMap          map[int][]int
	Err               error
}

func (le *LogicalExpr) setData(cexpr, lexpr *Expression, newLine int) error {
	// 循环现有的条件列表
	for cIndex := range le.CaseMultipleExpr {
		// 条件列表进行比对，具有相同元素则添加逻辑
		if CompareSlice(le.CaseMultipleExpr[cIndex].expr, cexpr.expr) {
			for lIndex := range le.LogicMultipleExpr {
				if CompareSlice(le.LogicMultipleExpr[lIndex].expr, lexpr.expr) {
					le.Err = errors.New(fmt.Sprintf("%s:第[%d]与[%d]行，[%s:%s]逻辑重复--[%v]{%v}",
						le.CaseMultipleExpr[cIndex].filePath, le.CaseMultipleExpr[cIndex].line, newLine, le.device, le.action, cexpr.str, lexpr.str),
					)
					return le.Err
				}
			}
			// 在逻辑列表添加逻辑表达式
			le.LogicMultipleExpr = append(le.LogicMultipleExpr, lexpr)
			// 设置当前条件表达式列表的index 对应哪一个逻辑表达式列表的最后一个index
			le.indexMap[cIndex] = append(le.indexMap[cIndex], len(le.LogicMultipleExpr)-1)
			//le.Line = newLine
			return nil
		}
	}
	// 在逻辑列表添加逻辑表达式
	le.LogicMultipleExpr = append(le.LogicMultipleExpr, lexpr)
	// 在条件列表添加条件表达式
	le.CaseMultipleExpr = append(le.CaseMultipleExpr, cexpr)
	caseLen := le.caseLength()
	// 设置最后条件表达式列表的index 对应哪一个逻辑表达式列表的最后一个index
	if le.indexMap == nil {
		indexMap := make(map[int][]int)
		le.indexMap = indexMap
	}
	le.indexMap[caseLen-1] = append(le.indexMap[caseLen-1], len(le.LogicMultipleExpr)-1)
	//le.Line = newLine
	return nil
}

func (le *LogicalExpr) Diff(newLogicalExpr *LogicalExpr) []*ExprCheck {
	var ecs []*ExprCheck
	// 复制一份CaseMultipleExpr
	copyCaseMultipleExpr := make([]*Expression, len(newLogicalExpr.CaseMultipleExpr))
	copy(copyCaseMultipleExpr, newLogicalExpr.CaseMultipleExpr)

	//if le.Line == 658 {
	//	fmt.Println(519)
	//}
	for caseIndex := range le.CaseMultipleExpr {
		caseExpr := le.CaseMultipleExpr[caseIndex]
		caseEC := NewDefaultExprCheck(CaseCheckType, caseExpr.line, caseExpr.filePath, caseExpr.FullStr, le.device, le.action)
		caseEC.expr = caseExpr
		// 在CaseMultipleExpr中找出目标情况条件
		fIndex := le.CaseMultipleExpr[caseIndex].findSameExpr(newLogicalExpr.CaseMultipleExpr)

		if fIndex == -1 {
			caseEC.message = "缺少的情况条件："
		} else {
			// 通过找到相同CaseExpr的下标 ,删除CaseExpr，
			cIndex := le.CaseMultipleExpr[caseIndex].findSameExpr(copyCaseMultipleExpr)
			if cIndex == -1 {
				fmt.Println("情况异常")
				panic("findSameExpr -1")
			}
			copyCaseMultipleExpr = append(copyCaseMultipleExpr[:cIndex], copyCaseMultipleExpr[cIndex+1:]...)
			// 处理相同CaseExpr的， 判断逻辑表达式是否相等
			srcIndexS, _ := le.indexMap[caseIndex]
			dstIndexS, _ := newLogicalExpr.indexMap[fIndex]
			caseEC.childCheck = le.diffLogical(srcIndexS, dstIndexS, newLogicalExpr)
			if len(caseEC.childCheck) > 0 {
				caseEC.message = "当前情况条件存在差异:"
			} else if len(caseEC.childCheck) == 0 {
				caseEC.message = "=="
			}
		}
		if caseEC.message != "==" {
			ecs = append(ecs, caseEC)
		}
	}
	// 剩余的 CaseMultipleExpr 即为多处理的。
	for i := range copyCaseMultipleExpr {
		caseEC := NewDefaultExprCheck(CaseCheckType, newLogicalExpr.Line, newLogicalExpr.filePath, newLogicalExpr.FullStr, newLogicalExpr.device, newLogicalExpr.action)
		caseEC.message = "多出的情况条件的逻辑："
		caseEC.expr = copyCaseMultipleExpr[i]
		ecs = append(ecs, caseEC)
	}
	if le.Err != nil {
		ecs = append(ecs, NewMessageExprCheck(ErrorCheckType, le.Line, le.Err.Error(), le.filePath, le.FullStr, nil))
	}
	return ecs
}

func (le *LogicalExpr) diffLogical(srcIndexS, dstIndexS []int, dstLE *LogicalExpr) []*ExprCheck {
	var ecs []*ExprCheck
	var dstMLogicalExpr []*Expression
	var targetExpr *Expression
	var isCheckedLogic int
	//newExpr := dstLE.LogicMultipleExpr
	// 通过目标逻辑序列 dstIndexS 获取到对应的逻辑序列列表
	for i := range dstIndexS {
		dstMLogicalExpr = append(dstMLogicalExpr, dstLE.LogicMultipleExpr[dstIndexS[i]])
	}

	// 循环源逻辑序列的 srcIndexS ，逐一比对源逻辑序列与目标逻辑序列
	for i := range srcIndexS {
		nowExpr := le.LogicMultipleExpr[srcIndexS[i]]
		lec := NewBaseExprCheck(LogicalCheckType, nowExpr.line, nowExpr.filePath, nowExpr.FullStr)
		var missExpr, moreExpr []string
		//if le.Line == 993 {
		//	fmt.Println(2878)
		//}
		//targetExpr := &Expression{}
		if len(dstMLogicalExpr) == 0 {
			// 如果目标逻辑序列未0 ，则表示当前逻辑序列都是多出来的
			moreExpr = le.LogicMultipleExpr[srcIndexS[i]].expr
		}
		isCheckedLogic = 0
		for j := range dstMLogicalExpr {

			// 查找不同的逻辑序列
			_missExpr, _moreEXPR := FindSliceStrDiff(nowExpr.expr, dstMLogicalExpr[j].expr)
			// 获取不同的逻辑序列（缺少的+多出的）总序列数量，
			if GetMultipleSliceLen(_missExpr, _moreEXPR) == 0 {
				// (差异序列总数量)新获取的为0，则表示没有差异。把（差异序列总数量）重新置为0
				missExpr, moreExpr = make([]string, 0), make([]string, 0)
				// 已处理的逻辑序列index 保存起来
				isCheckedLogic = j
				// 已经找到了相同的逻辑序列则，跳出该次循环
				break
			} else if GetMultipleSliceLen(_missExpr, _moreEXPR) < GetMultipleSliceLen(missExpr, moreExpr) || GetMultipleSliceLen(missExpr, moreExpr) == 0 {
				// (差异序列总数量)新获取的与历史的比较，最少的则保存起来，如果历史的为0，则保存最新的
				missExpr, moreExpr = _missExpr, _moreEXPR
				// 已处理的逻辑序列index 保存起来
				isCheckedLogic = j
				continue
			}
		}
		if len(dstMLogicalExpr) > 0 {
			targetExpr = dstMLogicalExpr[isCheckedLogic]
			targetExpr.Marshal()
			//fmt.Println("targetExpr", targetExpr.str)
			// 使用已处理的逻辑序列index 来删除已比对的目标逻辑序列
			dstMLogicalExpr = append(dstMLogicalExpr[:isCheckedLogic], dstMLogicalExpr[isCheckedLogic+1:]...)
		} else {
			targetExpr = nil
		}
		if len(missExpr) > 0 {
			lec.AppendDiffChild(MissExpression, nowExpr.line, nowExpr.filePath, nowExpr.FullStr, targetExpr, missExpr)
		}
		if len(moreExpr) > 0 {
			lec.AppendDiffChild(MoreExpression, nowExpr.line, nowExpr.filePath, nowExpr.FullStr, targetExpr, moreExpr)
		}
		// 如果没有差异则 跳过该次循环, 不添加记录
		if GetMultipleSliceLen(missExpr, moreExpr) == 0 {
			continue
		}
		// 保存当前处理的逻辑序列内容
		lec.expr = le.LogicMultipleExpr[srcIndexS[i]]
		lec.message = "当前逻辑存在差异"
		// 添加到检查结果序列
		ecs = append(ecs, lec)
	}
	// 循环剩余部分目标逻辑序列， 这部分相对源序列来说是多出来部分
	for index := range dstMLogicalExpr {

		lec := NewBaseExprCheck(LogicalCheckType, dstLE.Line, dstLE.filePath, dstLE.FullStr)
		lec.AppendDiffChild(MissExpression, dstMLogicalExpr[index].line, dstMLogicalExpr[index].filePath, dstMLogicalExpr[index].FullStr, dstMLogicalExpr[index], dstMLogicalExpr[index].expr)
		// 目标文件多余部分逻辑，不能保存到expr中，只能保存动作child的target中
		//lec.expr = dstMLogicalExpr[index]
		lec.message = "当前逻辑存在差异"
		// 添加到检查结果序列
		ecs = append(ecs, lec)
	}
	return ecs

}

//func (le *LogicalExpr) filter(exprS []*Expression)  {
//
//	return len(le.CaseMultipleExpr)
//}

func (le *LogicalExpr) caseLength() int {
	return len(le.CaseMultipleExpr)
}

func NewLogicalExpr(filePath, fullStr, device, action string, line int) *LogicalExpr {
	return &LogicalExpr{
		filePath: filePath,
		Line:     line,
		device:   device,
		action:   action,
		FullStr:  fullStr,
	}
}
